package com.basic.ui.list

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.viewbinding.ViewBinding
import com.basic.ui.view.inflate

/**
 * RecycleView 条目数据类型接口
 */
interface IType {
    fun getType(): Int
}

interface ItemTypeBinder<in T, VH : BaseHolder> : IType {
    fun bindData(holder: VH, data: T, position: Int)
    fun bindPayload(holder: VH, data: T, position: Int, payloads: List<Any>) {}
    fun createHolder(parent: ViewGroup): VH

    /**
     * userd for GridLayoutManager, 表示这种类型的item占几个span.
     * -1 表示full span
     */
    fun getSpanSize(): Int {
        return -1
    }
}

open class ItemLayoutBinder<T>(val layoutId: Int, val spanSize: Int = -1) :
    ItemTypeBinder<T, BaseHolder> {
    private var binder: ItemUpdater<BaseHolder, T>? = null

    constructor(layoutId: Int, spanSize: Int = -1, binder: ItemUpdater<BaseHolder, T>?) : this(
        layoutId,
        spanSize
    ) {
        this.binder = binder
    }

    override fun bindData(holder: BaseHolder, data: T, position: Int) {
        binder?.invoke(holder, data, position)
    }

    override fun createHolder(parent: ViewGroup): BaseHolder {
        return BaseHolder(parent.inflate(layoutId, false))
    }

    override fun getType(): Int {
        return 0
    }

    override fun getSpanSize(): Int {
        return spanSize
    }
}

open class ItemBindingBinder<VB : ViewBinding, T>(
    val spanSize: Int = -1,
    val inflate: (LayoutInflater, ViewGroup?, Boolean) -> VB
) :
    ItemTypeBinder<T, BaseHolder> {
    private var binder: ItemUpdater<VB, T>? = null

    constructor(
        spanSize: Int = -1,
        inflate: (LayoutInflater, ViewGroup?, Boolean) -> VB,
        binder: ItemUpdater<VB, T>?
    ) : this(spanSize, inflate) {
        this.binder = binder
    }

    override fun bindData(holder: BaseHolder, data: T, position: Int) {
        binder?.invoke(holder.getViewBinding<VB>()!!, data, position)
    }

    override fun createHolder(parent: ViewGroup): BaseHolder {
        val viewBinding = inflate(LayoutInflater.from(parent.context), parent, false)
        return BaseHolder(viewBinding.root).apply {
            this.viewBinding = viewBinding
        }
    }

    override fun getSpanSize(): Int {
        return spanSize
    }

    override fun getType(): Int {
        return 0
    }
}

typealias ItemUpdater<Holder, Data> = Holder.(data: Data, pos: Int) -> Unit
